// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: schedule_test.cpp 228 2008-09-15 13:35:23Z heavyzheng $
//

#include <zzheng/quant/dates/quant_dates_test_cases.hpp>
#include <zzheng/quant/dates.hpp>
#include <zzheng/test_logging.hpp>

#include <boost/test/unit_test.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <string>
#include <iostream>

namespace zzheng {
namespace test {

    namespace {

        quant::adjusted_period make_adjusted_period(const quant::date& unadjusted_start,
                                                    const quant::date& adjusted_start,
                                                    const quant::date& unadjusted_end,
                                                    const quant::date& adjusted_end) {
            quant::adjusted_date start(adjusted_start, unadjusted_start);
            quant::adjusted_date end  (adjusted_end,   unadjusted_end);
            return std::make_pair(start, end);
        }

    } // anonymous namespace

    ////////////////////////////////////////////////////////////////////////////////////////////////

    //! Generates schedule using daily frequency, when all periods are regular. Thus stub has no
    //! effect. The rolling convention used in this test case is modified following.
    void test_daily_freq() {

        info("Running test case: test_daily_freq");

        quant::calendar cal = quant::get_dummy_calendar();
        quant::date start(2009, 1, 31);
        quant::date end  (2009, 2,  8);
        quant::duration freq = quant::make_days(1);
        quant::schedule results;
        quant::schedule expected;

        expected.push_back( make_adjusted_period(quant::date(2009, 1, 31),
                                                 quant::date(2009, 1, 30),
                                                 quant::date(2009, 2,  1),
                                                 quant::date(2009, 2,  2)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  2),
                                                 quant::date(2009, 2,  2),
                                                 quant::date(2009, 2,  3),
                                                 quant::date(2009, 2,  3)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  3),
                                                 quant::date(2009, 2,  3),
                                                 quant::date(2009, 2,  4),
                                                 quant::date(2009, 2,  4)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  4),
                                                 quant::date(2009, 2,  4),
                                                 quant::date(2009, 2,  5),
                                                 quant::date(2009, 2,  5)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  5),
                                                 quant::date(2009, 2,  5),
                                                 quant::date(2009, 2,  6),
                                                 quant::date(2009, 2,  6)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  6),
                                                 quant::date(2009, 2,  6),
                                                 quant::date(2009, 2,  7),
                                                 quant::date(2009, 2,  9)) );

        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::short_first,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::short_last,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::long_first,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::long_last,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        results.clear();
        BOOST_CHECK_NO_THROW(
            quant::generate_schedule(start,
                                     end,
                                     freq,
                                     true,
                                     quant::no_stub,
                                     quant::mod_following,
                                     cal,
                                     results)
        );
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////

    void test_stub_types() {

        info("Running test case: test_stub_types");

        quant::calendar cal = quant::get_dummy_calendar();
        quant::date start(2009, 1, 31);
        quant::date end  (2009, 2, 17);
        quant::duration freq = quant::make_weeks(1);
        quant::schedule results;
        quant::schedule expected;

        //
        // Short last stub.
        //
        expected.clear();
        expected.push_back( make_adjusted_period(quant::date(2009, 1, 31),
                                                 quant::date(2009, 1, 30),
                                                 quant::date(2009, 2,  7),
                                                 quant::date(2009, 2,  9)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  7),
                                                 quant::date(2009, 2,  9),
                                                 quant::date(2009, 2, 14),
                                                 quant::date(2009, 2, 16)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2, 14),
                                                 quant::date(2009, 2, 16),
                                                 quant::date(2009, 2, 17),
                                                 quant::date(2009, 2, 17)) );
        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::short_last,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        //
        // Long last stub.
        //
        expected.clear();
        expected.push_back( make_adjusted_period(quant::date(2009, 1, 31),
                                                 quant::date(2009, 1, 30),
                                                 quant::date(2009, 2,  7),
                                                 quant::date(2009, 2,  9)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  7),
                                                 quant::date(2009, 2,  9),
                                                 quant::date(2009, 2, 17),
                                                 quant::date(2009, 2, 17)) );
        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::long_last,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        //
        // Short first stub.
        //
        expected.clear();
        expected.push_back( make_adjusted_period(quant::date(2009, 1, 31),
                                                 quant::date(2009, 1, 30),
                                                 quant::date(2009, 2,  3),
                                                 quant::date(2009, 2,  3)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2,  3),
                                                 quant::date(2009, 2,  3),
                                                 quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 10)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 17),
                                                 quant::date(2009, 2, 17)) );
        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::short_first,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        //
        // Long first stub.
        //
        expected.clear();
        expected.push_back( make_adjusted_period(quant::date(2009, 1, 31),
                                                 quant::date(2009, 1, 30),
                                                 quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 10)) );
        expected.push_back( make_adjusted_period(quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 10),
                                                 quant::date(2009, 2, 17),
                                                 quant::date(2009, 2, 17)) );
        results.clear();
        quant::generate_schedule(start,
                                 end,
                                 freq,
                                 true,
                                 quant::long_first,
                                 quant::mod_following,
                                 cal,
                                 results);
        BOOST_CHECK_EQUAL_COLLECTIONS( results.begin(),  results.end(),
                                       expected.begin(), expected.end() );

        //
        // No stub: expecting exception.
        //
        results.clear();
        BOOST_CHECK_THROW(
            quant::generate_schedule(start,
                                     end,
                                     freq,
                                     true,
                                     quant::no_stub,
                                     quant::mod_following,
                                     cal,
                                     results),
            quant::date_error
        );
    }

    ////////////////////////////////////////////////////////////////////////////////////////////////

    void add_schedule_test_cases(boost::unit_test::test_suite& suite) {
        suite.add( BOOST_TEST_CASE(&test_daily_freq) );
        suite.add( BOOST_TEST_CASE(&test_stub_types) );
    }

} // namespace zzheng::test
} // namespace zzheng


